module Palantir
  class Base

    attr_accessor :data, :default

    # Create a Palantir.
    #
    # Example:
    #   >> p = Palantir::Base.new([{key: 'key', value: 'value'}])
    #   => #<Palantir::Base:0x007fe1de9642f0 @data=[{:foo=>"bar"}], @default=0>
    #
    # Arguments:
    #   data: (Array)
    #   default: (Integer)
    def initialize(data, default = 0)
      @data = data
      @default = default
    end

    # Return the @data size in the Palantir instance.
    #
    def size
      @data.count
    end

    # Filter data with a 'where' clause given a pair <key, value>.
    # Chainable
    #
    # Example:
    #   [{class: 'wizard', name: 'Gandalf'},{class: 'burglar', name: 'Bilbo'},{class: 'wizard', name: 'Saruman'}]
    #   >> palantir.where(:class, 'wizard').where(:name, 'Gandalf')
    #
    # Arguments:
    #   key: (Symbol)
    #   value: (String, Integer, Decimal...)
    def where(key, value)
      filtered_data = @data.select do |element|
        element.has_key?(key) && element.fetch(key) == value
      end
      self.class.new(filtered_data, @default)
    end

    # Filter data that have a given key.
    # Chainable
    #
    # Example:
    #   [{class: 'wizard', name: 'Gandalf', beard: 'grey'},{class: 'burglar', name: 'Bilbo'},{class: 'wizard', name: 'Saruman', beard:'grey'}]
    #   >> palantir.with(:beard)
    #
    # Arguments:
    #   key: (Symbol)
    #   value: (String, Integer, Decimal...)
    def with(key)
      filtered_data = @data.select do |element|
        element.has_key?(key)
      end
      self.class.new(filtered_data, @default)
    end

    # Sum data of a specific key, if any, otherwise add the default_value.
    # This ends a chain of 'where'.
    #
    # Example:
    #   >> palantir.where(:class, 'wizard').sum(:age)
    #
    # Arguments:
    #   key: (Symbol)
    #   first_value: (Integer)
    def sum(key, first_value = 0)
      @data.reduce(first_value) do |sum, element|
        sum += element.fetch(key){ @default }
      end
    end
  end
end
